package com.winit.feature.manager;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.winit.common.base.StandardFeedBackInfo;
import com.winit.common.base.bean.ExecuteResult;
import com.winit.common.base.web.BaseController;
import com.winit.common.constants.IdTag;
import com.winit.common.util.Constants;
import com.winit.common.util.treeUtils.BaseTree;
import com.winit.common.util.treeUtils.TreeUtil;
import com.winit.commons.util.HttpClientUtil;
import com.winit.commons.util.SeqGenerate;
import com.winit.config.model.Config;
import com.winit.config.service.IConfigService;
import com.winit.feature.model.*;
import com.winit.feature.repository.*;
import com.winit.feature.service.FeatureVersionGenerator;
import com.winit.feature.web.FeatureController;
import com.winit.flow.manager.FlowManager;
import com.winit.flow.model.VersionHistory;
import com.winit.indexing.model.Indexing;
import com.winit.indexing.model.IndexingId;
import com.winit.indexing.service.IIdexingService;
import com.winit.menu.model.MatrixMenu;
import com.winit.menu.service.IMenuService;
import com.winit.page.model.Page;
import com.winit.page.service.IPageService;
import com.winit.requirement.manager.BrdRequirementManager;
import com.winit.requirement.model.BrdRequirement;
import com.winit.requirement.model.ReqHistory;
import org.hibernate.annotations.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;

@Component
public class FeatureManager {

    private static Logger logger = LoggerFactory.getLogger(FeatureManager.class);

    @Value("${path.prototype}")
    private String PROTOTYPE_PATH;

    @Autowired
    private IPageService pageService;

    @Autowired
    private FeatureRepository featureRepository;
    @Autowired
    private FeatureOperations featureOperations;

    @Autowired
    private IConfigService configService;
    @Autowired
    private IIdexingService indexingService;
    @Autowired
    private FeatureReqRepository featureReqRepository;
    @Autowired
    private IMenuService menuService;
    @Autowired
    private IFeatureHistoryRepository featureHistoryRepository;
    @Autowired
    private FeatureVersionHistoryRepository versionHistoryRepository;
    @Autowired
    private PathContainer pathContainer;
    @Autowired
    private FlowManager flowManager;
    @Autowired
    private BrdRequirementManager brdRequirementManager;

    public List<BaseTree> getFeatureBaseTree(String sys, String menuId) {
        MatrixMenu menu = this.menuService.getMenu(null, sys);
        if (menu == null) {
            return null;
        }
        BaseTree baseTree = this.convertToBaseTree(menu, true);
        List<BaseTree> rs = new ArrayList<>();
        rs.add(baseTree);
        return rs;
    }

    private BaseTree convertToBaseTree(MatrixMenu matrixMenu, boolean setPath) {
        MatrixMenu meta = new MatrixMenu();
        BeanUtils.copyProperties(matrixMenu, meta);
        meta.setChild(null);
        BaseTree baseTree = TreeUtil.getTree(meta);

        List<BaseTree> children = new ArrayList<>();
        baseTree.setChildren(children);
        List<MatrixMenu> matrixMenus = matrixMenu.getChild();
        if (!CollectionUtils.isEmpty(matrixMenus)) {
//            List<BaseTree> children = new ArrayList<>();
            for (MatrixMenu child : matrixMenus) {
                BaseTree node = this.convertToBaseTree(child, setPath);
                children.add(node);
            }
        }
//        if ("3".equals(matrixMenu.getLevel())) { //3级menu直接获取page
        List<BaseTree> pagechildren = this.getChildrenOfPage(matrixMenu.getId(), setPath);
//            if (!CollectionUtils.isEmpty(children)) {
//                baseTree.setChildren(children);
//            }
//            return baseTree;
//        }
        if (!CollectionUtils.isEmpty(pagechildren)) {
            children.addAll(pagechildren);
        }
        return baseTree;
    }

    private List<BaseTree> getChildrenOfPage(String menuId, boolean setPath) {
        List<Page> pages = this.pageService.getPagesForMenuId(menuId, setPath);
        if (CollectionUtils.isEmpty(pages)) {
            return null;
        }
        List<BaseTree> rs = new ArrayList<>();
        for (Page page : pages) {
            page.setMenuPath(this.pathContainer.getPathById(page.getId(), false));
            rs.add(TreeUtil.getTree(page));
        }
        return rs;
    }


    public List<Feature> getPageFeatures(String pageId) {
        IndexingId indexingId = new IndexingId("page_feature_indexing", pageId);
        Indexing pageFeatureIndexing = this.indexingService.getIndexing(indexingId);
        if (null == pageFeatureIndexing || CollectionUtils.isEmpty(pageFeatureIndexing.getIndexMap())) {
            return null;
        }
        Map<String, String> reqFeatureIds = pageFeatureIndexing.getIndexMap();
        Set<String> featureIds = reqFeatureIds.keySet();
        List<String> featureIdsLst = new ArrayList<>();
        featureIdsLst.addAll(featureIds);
        List<Feature> features = this.featureRepository.findByFeatureIds(featureIdsLst);
        if (CollectionUtils.isEmpty(features)) {
            return features;
        }
        Feature prototype = null;
        Iterator<Feature> iterator = features.iterator();
        Feature temp = null;
        while (iterator.hasNext()) {
            temp = iterator.next();
            temp.setPageId(pageId);
            temp.setPath(this.pathContainer.getPathById(temp.getId(), false));
            if ("prototype".equalsIgnoreCase(temp.getType())) {
                prototype = temp;
                iterator.remove();
            }
        }
        if (null == prototype) {
            return features;
        }
        List<Feature> rs = new ArrayList<>();
        rs.add(prototype);
        if (!CollectionUtils.isEmpty(features)) {
            rs.addAll(sortFeature(features));
        }
        return rs;
    }

    /**
     * @param id，如果指定了id，则reqid不再做为feature的搜索条件
     * @param sys
     * @param reqId                             req = -1 || null 时不作为feature的搜索条件
     * @param path
     * @param withAttr
     * @return
     */
    public ExecuteResult getFeature(String id, String sys, String reqId, String path, String withAttr, String withPrototype) {
        ExecuteResult executeResult = new ExecuteResult();
        Feature searchCondition = new Feature();
        searchCondition.setId(id);
//        if((!StringUtils.isEmpty(reqId)) && (!"-1".equals(reqId)) && (StringUtils.isEmpty(id))){
//            searchCondition.setReqId(reqId);
//        }
        searchCondition.setSys(sys);
        searchCondition.setPath(path);
        List<Feature> features = this.featureOperations.findByProperNotNull(searchCondition);
        if (CollectionUtils.isEmpty(features)) {
            return executeResult;
        }
        for (Feature feature : features) {
            feature.setPath(this.pathContainer.getPathById(feature.getId(), false));
        }

//        Feature temp = null;
//        boolean excludeAdd = "-1".equals(reqId);
//        boolean withAttr_ = "1".equals(withAttr);
//        boolean excludeProto = "0".equals(withPrototype);
//        while (iterator.hasNext()){
//            temp = iterator.next();
//            if ((excludeAdd && "ADD".equalsIgnoreCase(temp.getStatus())) || excludeProto){
//                iterator.remove();
//            }else if ()
//        }
        if ("-1".equals(reqId)) {
            Iterator<Feature> iterator = features.iterator();
            Feature temp = null;
            while (iterator.hasNext()) {
                temp = iterator.next();
                if ("ADD".equalsIgnoreCase(temp.getStatus())) {
                    iterator.remove();
                }
            }
            if (CollectionUtils.isEmpty(features)) {
                return executeResult;
            }
        }

        if ("0".equals(withPrototype)) {
            Iterator<Feature> iterator = features.iterator();
            Feature temp = null;
            while (iterator.hasNext()) {
                temp = iterator.next();
                if ("prototype".equalsIgnoreCase(temp.getType())) {
                    iterator.remove();
                }
            }
            if (CollectionUtils.isEmpty(features)) {
                return executeResult;
            }
        }

        if ("1".equals(withAttr)) {
            for (Feature feature : features) {
                try {
                    this.featureAutoConfigure(feature, reqId);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    executeResult.setCode(BaseController.REQUEST_ERROR);
                    executeResult.setMsg(e.getMessage());
                    return executeResult;
                }
            }
        }
        executeResult.setData(features);
        return executeResult;
    }

    private void reflushFeatureReqIndexing(String featureId, String reqId, int mode) throws Exception {
        IndexingId indexingId = new IndexingId("feature_req_indexing", featureId);
        if (mode == 1) {
            Map<String, String> indexMap = new HashMap<>();
            indexMap.put(reqId, "");
            this.indexingService.indexing(new Indexing(indexingId, indexMap));
        } else if (mode == -1) {
            this.indexingService.removeIfExists(indexingId, new String[]{reqId});
        } else {
            throw new Exception("mode 只能为-1或者1");
        }
    }

    public ExecuteResult relateToPage(String reqId, String featureId, String pageId) {
        ExecuteResult executeResult = new ExecuteResult();
        Feature feature = this.featureRepository.findOne(featureId);
        if (null == feature) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg("未找到指定的feature, featureId:" + featureId);
            return executeResult;
        }
        /** 刷新feature与req的对应关系 */
        if (!"-1".equals(reqId)) {
            try {
                this.flushIndexingForReqFeature(feature, reqId, 1);
                this.reflushFeatureReqIndexing(featureId, reqId, 1);
                /** 复制一份feature config（作为与req对应的存在) */
                FeatureReqId featureReqId = new FeatureReqId(featureId, reqId);
                FeatureReq dbFeatureReq = this.featureReqRepository.findOne(featureReqId);
                if (null == dbFeatureReq && (!StringUtils.isEmpty(feature.getAttrConfigId()))) {
                    Config config = this.configService.getConfigMap(feature.getAttrConfigId(), false);
                    if (null != config) {
                        config.setId(null);
                        Map<String, String> configMap = config.getKVMap();
                        //20180226
                        configMap.put("from_master_version", configMap.get("version"));
                        this.updateVersionInfoForFeature(configMap, FeatureVersionGenerator.getVersionNo(), configMap.get("version"), configMap.get("req_snapshot"));
                        config = this.configService.saveConfig(config);
                        FeatureReq newFeatureReq = new FeatureReq();
                        newFeatureReq.setId(featureReqId);
                        newFeatureReq.setAttrConfigId(config.getId());
                        this.featureReqRepository.save(newFeatureReq);
                        executeResult = this.operateFlowForFeatureModify(reqId, featureId);
                        if (!executeResult.isSuccess()) {
                            return executeResult;
                        }
                    }
                }

            } catch (Exception e) {
                executeResult.setCode(BaseController.REQUEST_ERROR);
                executeResult.setMsg(e.getMessage());
                return executeResult;
            }
        }
        /** 刷新page与feature的关系page_feature_indexing */
        IndexingId indexingId = new IndexingId("page_feature_indexing", pageId);
        Map<String, String> indexMap = new HashMap<>();
        indexMap.put(featureId, reqId);
        Indexing indexing = new Indexing(indexingId, indexMap);
        try {
            this.indexingService.indexing(indexing);
        } catch (Exception e) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg(e.getMessage());
            return executeResult;
        }
        /** 刷新feature与page的关系feature_page_indexing */
        IndexingId indexingIdFeatureReq = new IndexingId("feature_page_indexing", featureId);
        Map<String, String> indexMap1 = new HashMap<>();
        indexMap1.put(pageId, reqId);
        Indexing indexingFeatureReq = new Indexing(indexingIdFeatureReq, indexMap1);
        try {
            this.indexingService.indexing(indexingFeatureReq);
        } catch (Exception e) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg(e.getMessage());
            return executeResult;
        }

        Feature update = new Feature();
        update.setId(featureId);
        update.setReqId(reqId);
        this.featureOperations.updatePropertiesNotNullById(update);
        pageService.updatePageChild(pageId, featureId, "add");

        return executeResult;
    }

    @CacheEvict(cacheNames = {"getAllElements"}, allEntries = true)
    public ExecuteResult createFeature(Feature feature) {
        ExecuteResult executeResult = new ExecuteResult();
        if (feature.getId() == null) {
            feature.setId(SeqGenerate.createId("FE"));
        }
        String reqId = feature.getReqId();
        if (reqId == null) {
            reqId = "-1";
            feature.setReqId(reqId);
        }
        if (StringUtils.isEmpty(feature.getStatus())) {
            String status = "-1".equals(reqId) ? "ONLINE" : "ADD";
            feature.setStatus(status);
        }
        if (StringUtils.isEmpty(feature.getType())) {
            feature.setType("COMMON");
        } else {
            feature.setType(feature.getType().toUpperCase());
        }
        if (!StringUtils.isEmpty(feature.getSys())) {
            feature.setSys(feature.getSys().toUpperCase());
        }
        Map<String, String> attrs = feature.getAttr();
        attrs = null == attrs ? new HashMap<String, String>() : attrs;
        attrs.put("date", System.currentTimeMillis() + "");
//        if (!CollectionUtils.isEmpty(attrs)) {
        this.updateVersionInfoForFeature(attrs, FeatureVersionGenerator.getVersionNo(), "", "");
        Config config = new Config();
        config.setKVMap(attrs);
        Config dbOne = this.configService.saveConfig(config);
        feature.setAttrConfigId(dbOne.getId());
//        }
        this.featureRepository.save(feature);
        String pageId = feature.getPageId();
        if (!StringUtils.isEmpty(pageId)) {

            this.relateToPage(reqId, feature.getId(), pageId);
        }
//        if (!StringUtils.isEmpty(feature.getOriginalPageId())){
        this.pathContainer.add(feature.getId(), feature.getOriginalPageId(), feature.getFeatureName(), null);
//        }
        executeResult.setData(feature.getId());
        return executeResult;
    }
    @CacheEvict(cacheNames = {"getAllElements"}, allEntries = true)
    public ExecuteResult updateFeatureAttrForReq(String id, String reqId, Map<String, String> attr) {
        ExecuteResult executeResult = new ExecuteResult();
        Feature dbFeature = this.featureRepository.findOne(id);
        if (dbFeature == null) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg("指定的feature不存在");
            return executeResult;
        }
//        String dbReqId = dbFeature.getReqId();
//        if ((null != dbReqId) && (!"-1".equals(dbReqId)) && (!dbReqId.equals(reqId))){
//            executeResult.setCode(BaseController.REQUEST_ERROR);
//            executeResult.setMsg("指定的feature已被其它req占用，不能修改，reqId:" + dbReqId);
//            return executeResult;
//        }
        /** req = -1 修改主版本的情况 */
        if ("-1".equals(reqId) || StringUtils.isEmpty(reqId)) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg("该接口不处理理req为空或者-1的操作");
            return executeResult;
        }
//        if ("-1".equals(reqId)){
//            Config config = new Config();
//            config.setId(dbFeature.getAttrConfigId());
//            config.setKVMap(attr);
//            config = this.configService.saveConfig(config);
//            if (StringUtils.isEmpty(dbFeature.getAttrConfigId())){
//                Feature update = new Feature();
//                update.setId(id);
//                update.setAttrConfigId(config.getId());
//                this.featureOperations.updatePropertiesNotNullById(update);
//            }
//            return executeResult;
//        }
        /** 处理indexing */
        try {
            this.flushIndexingForReqFeature(dbFeature, reqId, 1);
            this.reflushFeatureReqIndexing(id, reqId, 1);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg(e.getMessage());
            return executeResult;
        }
        /** 处理featureReq记录与其对应的config */
        FeatureReqId featureReqId = new FeatureReqId(id, reqId);
        FeatureReq featureReq = this.featureReqRepository.findOne(featureReqId);
        String reqAttrConfigId = null == featureReq ? null : featureReq.getAttrConfigId();
        Config config = new Config();
        config.setId(reqAttrConfigId);
        if (featureReq == null || StringUtils.isEmpty(featureReq.getAttrConfigId())) {   //首次新建req-feature-config
            try {
                Config masterConfig = this.configService.getConfigMap(dbFeature.getAttrConfigId(), false);
                Map<String, String> masterConfigMap = masterConfig.getKVMap();
                this.updateVersionInfoForFeature(attr, FeatureVersionGenerator.getVersionNo(), masterConfigMap.get("version"), masterConfigMap.get("req_snapshot"));
                attr.put("from_master_version", masterConfigMap.get("version"));
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                executeResult.setCode(BaseController.REQUEST_ERROR);
                executeResult.setMsg(e.getMessage());
                return executeResult;
            }
        }

        config.setKVMap(attr);
        attr.put("date", System.currentTimeMillis() + "");
        config = this.configService.saveConfig(config);
        if (reqAttrConfigId == null) {
            FeatureReq persit = new FeatureReq();
            persit.setId(featureReqId);
            persit.setAttrConfigId(config.getId());
            this.featureReqRepository.save(persit);

            executeResult = this.operateFlowForFeatureModify(reqId, id);
        }
//        if(!reqId.equals(dbReqId)){
//        if(!"-1".equals(reqId)){
        if (!"ADD".equalsIgnoreCase(dbFeature.getStatus())) {
            Feature update = new Feature();
            update.setId(id);
            update.setStatus("UPDATE");
            update.setFeatureKind(attr.get("feature_type"));
//            update.setReqId(reqId);
            this.featureOperations.updatePropertiesNotNullById(update);
        }
        return executeResult;
    }

    private ExecuteResult operateFlowForFeatureModify(String reqId, String featureId) {
        ExecuteResult executeResult = new ExecuteResult();
        try {
            executeResult = flowManager.operateForFeatureModify(reqId, featureId);
            if ("0".equals(executeResult.getCode())) {
            } else {
                logger.error(executeResult.getDesc());
                executeResult.setToError();
                executeResult.setMsg(executeResult.getDesc());
                return executeResult;
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            executeResult.setToError();
            executeResult.setMsg(e.getMessage());
        }
        return executeResult;
    }

    /**
     * 该方法执行以下操作：
     * 1、移除指定req建立的feature与page的关系（page_feature_indexing/feature_page_indexing:若存在）
     * 2、移除feature的req版本(若存在)：matrix_feature_req --> config
     * 3、移除req_feature_indexing(若存在)中包含的feature_id
     * 4、若featureId对应的feature为：
     * add状态：删除feature,删除feature.masterAttrConfigId对应的config
     * 其它状态：将feature.status变为ondline, feature.reqId变为-1
     *
     * @param reqId
     * @param featureId
     * @return
     */
    public ExecuteResult dissociateRelation(String reqId, String featureId) {
        ExecuteResult executeResult = new ExecuteResult();
        Feature dbFeature = this.featureRepository.findOne(featureId);
        if (null == dbFeature) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg("指定的feature未找到, featureId:" + featureId);
            return executeResult;
        }
        executeResult = this.removeRelationBetweenPageAndFeature(featureId, reqId);
        if (!executeResult.isSuccess()) {
            return executeResult;
        }
        executeResult = this.removeRelationBetweenFeatureAndReq(featureId, reqId);
        if (!executeResult.isSuccess()) {
            return executeResult;
        }
//        try {
//            this.reflushFeatureReqIndexing(featureId, reqId, -1);
//        }catch (Exception e){
//            executeResult.setCode(BaseController.REQUEST_ERROR);
//            executeResult.setMsg(e.getMessage());
//            return executeResult;
//        }
//        FeatureReqId featureReqId = new FeatureReqId(featureId, reqId);
//        FeatureReq featureReq = this.featureReqRepository.findOne(featureReqId);
//        if (null != featureReq){
//            String configId = featureReq.getAttrConfigId();
//            if (!StringUtils.isEmpty(configId)){
//                this.configService.deleteConfigById(configId);
//            }
//            this.featureReqRepository.delete(featureReqId);
//        }
//        //移除indexing中的req_feature_indexing
//        try {
//            this.indexingService.removeIfExists(new IndexingId("req_feature_indexing", reqId), new String[]{featureId});
//        } catch (Exception e) {
//            logger.error(e.getMessage(), e);
//            executeResult.setCode(BaseController.REQUEST_ERROR);
//            executeResult.setMsg(e.getMessage());
//            //继续执行
//        }
        if ("ADD".equals(dbFeature.getStatus())) {
            //add状态的不再删除
//            this.featureRepository.delete(featureId);
//            String masterConfigId = dbFeature.getAttrConfigId();
//            if (!StringUtils.isEmpty(masterConfigId)){
//                this.configService.deleteConfigById(masterConfigId);
//            }
            return executeResult;
        } else {
            Indexing featureReqIndexing = this.indexingService.getIndexing(new IndexingId("feature_req_indexing", featureId));
            if (null == featureReqIndexing || CollectionUtils.isEmpty(featureReqIndexing.getIndexMap())) {   //没有其它req关联了
                Feature update = new Feature();
                update.setId(featureId);
                update.setStatus("ONLINE");
                update.setReqId("-1");
                this.featureOperations.updatePropertiesNotNullById(update);
            }
            return executeResult;
        }
    }

    /**
     * 移除指定 req的feature与page之间的关系(page_feature_indexing, feature_page_indexing)(若存在)，
     * 如果req为null，则移除feature与所有page之间的关系,feature与所有req的关系
     * @param featureId
     * @param reqId
     * @param cleanFeatureAndReq 是否强制清除feature与req之间的关系，若清除，则会清除req_feature_indexing, FeatureReq, req -feature-config
     * @return
     */
    /**    该方法改写为ExecuteResult removeRelationBetweenPageAndFeature(String featureId, String reqId)与ExecuteResult removeRelationBetweenFeatureAndReq(String featureId, String reqId)两个方法
     private ExecuteResult removeRelationBetweenPageAndFeature1(String featureId, String reqId, boolean cleanFeatureAndReq){
     ExecuteResult executeResult = new ExecuteResult();
     IndexingId indexingId = new IndexingId("feature_page_indexing", featureId);
     Indexing indexing = this.indexingService.getIndexing(indexingId);
     if (null == indexing) {
     return executeResult;
     }
     Map<String, String> indexMap = indexing.getIndexMap();
     if (CollectionUtils.isEmpty(indexMap)){
     return executeResult;
     }
     Set<String> pageIds = indexMap.keySet();
     List<String> removePages = new ArrayList<>();
     for (String pageId : pageIds){
     if (null != reqId && (!reqId.equals(indexMap.get(pageId)))){
     continue;
     }
     removePages.add(pageId);
     try {
     IndexingId tempId = new IndexingId("page_feature_indexing", pageId);
     //移除page中的feature
     this.indexingService.removeIfExists(tempId, new String[]{featureId});

     } catch (Exception e) {
     logger.error(e.getMessage(), e);
     executeResult.setCode(BaseController.REQUEST_ERROR);
     executeResult.setMsg(e.getMessage());
     return executeResult;
     }
     }
     if (!CollectionUtils.isEmpty(removePages)){
     try {
     //移除feature中的page
     this.indexingService.removeIfExists(indexingId, removePages.toArray(new String[]{}));
     } catch (Exception e) {
     logger.error(e.getMessage(), e);
     executeResult.setCode(BaseController.REQUEST_ERROR);
     executeResult.setMsg(e.getMessage());
     return executeResult;
     }
     }
     if (!cleanFeatureAndReq) {
     return executeResult;
     }
     List<FeatureReq> featureReqs = this.featureOperations.findFeatureReqByFeatureId(featureId);
     if (CollectionUtils.isEmpty(featureReqs)){
     return executeResult;
     }
     for(FeatureReq featureReq : featureReqs){
     if (null != reqId && (!reqId.equals(featureReq.getId().getReqId()))){
     continue;
     }
     String configId = featureReq.getAttrConfigId();
     if (!StringUtils.isEmpty(configId)){
     this.configService.deleteConfigById(configId);
     }
     this.featureReqRepository.delete(featureReq.getId());
     //移除indexing中的req_feature_indexing
     try {
     this.indexingService.removeIfExists(new IndexingId("req_feature_indexing", featureReq.getId().getReqId()), new String[]{featureId});
     this.indexingService.removeIfExists(new IndexingId("feature_req_indexing", featureId), new String[]{featureReq.getId().getReqId()});
     } catch (Exception e) {
     logger.error(e.getMessage(), e);
     executeResult.setCode(BaseController.REQUEST_ERROR);
     executeResult.setMsg(e.getMessage());
     return executeResult;
     }
     }
     return executeResult;
     }
     */

    /**
     * 移除指定 req的feature与page之间的关系(page_feature_indexing, feature_page_indexing)(若存在)，
     * 如果req为null，则移除feature与所有page之间的关系,feature与所有req的关系
     *
     * @param featureId 不能为null
     * @param reqId
     * @return
     */
    private ExecuteResult removeRelationBetweenPageAndFeature(String featureId, String reqId) {
        Assert.notNull(featureId, "featureId为能为null");
        ExecuteResult executeResult = new ExecuteResult();
        IndexingId indexingId = new IndexingId("feature_page_indexing", featureId);
        Indexing indexing = this.indexingService.getIndexing(indexingId);
        if (null == indexing) {
            return executeResult;
        }
        Map<String, String> indexMap = indexing.getIndexMap();
        if (CollectionUtils.isEmpty(indexMap)) {
            return executeResult;
        }
        Set<String> pageIds = indexMap.keySet();
        List<String> removePages = new ArrayList<>();
        for (String pageId : pageIds) {
            if (null != reqId && (!reqId.equals(indexMap.get(pageId)))) {
                continue;
            }
            removePages.add(pageId);
            try {
                IndexingId tempId = new IndexingId("page_feature_indexing", pageId);
                //移除page中的feature
                this.indexingService.removeIfExists(tempId, new String[]{featureId});

                pageService.updatePageChild(pageId, featureId, "remove");

            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                executeResult.setCode(BaseController.REQUEST_ERROR);
                executeResult.setMsg(e.getMessage());
                return executeResult;
            }
        }
        if (!CollectionUtils.isEmpty(removePages)) {
            try {
                //移除feature中的page
                this.indexingService.removeIfExists(indexingId, removePages.toArray(new String[]{}));
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                executeResult.setCode(BaseController.REQUEST_ERROR);
                executeResult.setMsg(e.getMessage());
                return executeResult;
            }
        }
        return executeResult;
    }

    /**
     * 该方法会清除req_feature_indexing, FeatureReq, req -feature-config
     *
     * @param featureId 不为null
     * @param reqId     reqId为null时清除feature与所有req的关系
     * @return
     */
    private ExecuteResult removeRelationBetweenFeatureAndReq(String featureId, String reqId) {
        /**
         * 可以按照feature_req_indexing来处理，
         * 但存在老旧数据并没有feature_req_indexing，这里按表matrix_feature_req来处理
         */
        Assert.notNull(featureId, "featureId为能为null");
        ExecuteResult executeResult = new ExecuteResult();
        List<FeatureReq> featureReqs = this.featureOperations.findFeatureReqByFeatureId(featureId);
        if (CollectionUtils.isEmpty(featureReqs)) {
            return executeResult;
        }
        for (FeatureReq featureReq : featureReqs) {
            if (null != reqId && (!reqId.equals(featureReq.getId().getReqId()))) {
                continue;
            }
            String configId = featureReq.getAttrConfigId();
            if (!StringUtils.isEmpty(configId)) {
                this.configService.deleteConfigById(configId);
            }
            this.featureReqRepository.delete(featureReq.getId());
            //移除indexing中的req_feature_indexing
            try {
                this.indexingService.removeIfExists(new IndexingId("req_feature_indexing", featureReq.getId().getReqId()), new String[]{featureId});

                executeResult = brdRequirementManager.operateRelationBetweenReqAndFeature(featureId, reqId, "-1");
                if (!"0".equals(executeResult.getCode())) {
                    logger.error(executeResult.getDesc());
                    return executeResult;
                }
                this.indexingService.removeIfExists(new IndexingId("feature_req_indexing", featureId), new String[]{featureReq.getId().getReqId()});
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                executeResult.setCode(BaseController.REQUEST_ERROR);
                executeResult.setMsg(e.getMessage());
                return executeResult;
            }
        }
        return executeResult;
    }


    public ExecuteResult featureOccupy(String reqId, String id) {
        ExecuteResult executeResult = new ExecuteResult();
        Feature dbFeature = this.featureRepository.findOne(id);
//        String dbReqId = dbFeature.getReqId();
//        if(null != dbReqId && (!"-1".equals(dbReqId)) && (!dbReqId.equals(reqId))){
//
//            executeResult.setCode(BaseController.REQUEST_ERROR);
//            executeResult.setMsg("feature 已经被其它req占用, reqId:" + dbReqId);
//            return executeResult;
//        }
        Map<String, String> attrs = null;
        try {
            attrs = this.configService.getConfigMap(dbFeature.getAttrConfigId(), false).getKVMap();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg(e.getMessage());
            return executeResult;
        }
        return this.updateFeatureAttrForReq(id, reqId, attrs);
    }

    @CacheEvict(cacheNames = {"getAllElements"}, allEntries = true)
    public ExecuteResult deleteFeature(String featureId) {
        ExecuteResult executeResult = new ExecuteResult();
        Feature dbFeature = this.featureRepository.findOne(featureId);
        if (null == dbFeature) {
//            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg("指定的feature不存在");
            return executeResult;
        }
//        String dbReqId = dbFeature.getReqId();

//        if ((!"-1".equals(dbReqId)) && null != dbReqId){    //有req关联，移除与指定feature之间的关系
//           executeResult = this.dissociateRelation(dbReqId, featureId);
//           if (!executeResult.isSuccess()){
//               return executeResult;
//           }
//        }
//        dbFeature = this.featureRepository.findOne(featureId);
//        if (null != dbFeature){    //若为add状态一定走了以上分支,或者依然存在的情况
        //非add状态下，移除feature与任何其它page的关系（若存在）
//            executeResult = this.removeRelationBetweenPageAndFeature(featureId, null, true);
        executeResult = this.removeRelationBetweenPageAndFeature(featureId, null);
        if (!executeResult.isSuccess()) {
            return executeResult;
        }
        executeResult = this.removeRelationBetweenFeatureAndReq(featureId, null);
        if (!executeResult.isSuccess()) {
            return executeResult;
        }

        this.featureRepository.delete(featureId);
//            this.indexingService.deleteIndex(new IndexingId("feature_req_indexing", featureId));
        if (!StringUtils.isEmpty(dbFeature.getAttrConfigId())) {
            this.configService.deleteConfigById(dbFeature.getAttrConfigId());
        }


//        }
        this.pathContainer.remove(featureId);
        if ("PROTOTYPE".equalsIgnoreCase(dbFeature.getType())) {  //删除其下的所有axure文件
            String dir = PROTOTYPE_PATH + featureId;
            String command = "rm -rf " + dir;
            try {
                logger.info("execute command when delete prototype feature:" + command);
                Process process = Runtime.getRuntime().exec(command);
                process.waitFor();
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                executeResult.setToError();
                executeResult.setMsg(e.getMessage());
            }
        }
        pageService.updatePageChild(dbFeature.getOriginalPageId(), featureId, "remove");
        return executeResult;
    }

    public ExecuteResult updateFeatureConfig(Feature feature) {
        ExecuteResult executeResult = new ExecuteResult();

        if (feature.getId() == null) {
            String msg = "id为空，更新终止";
            logger.error(msg);
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg(msg);
            return executeResult;
        }
        String reqId = feature.getReqId();
        if (StringUtils.isEmpty(reqId)) {
            String msg = "reqId为空，更新终止.";
            logger.error(msg);
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg(msg);
            return executeResult;
        }
        if ("-1".equals(reqId)) {
            String msg = "reqId为-1，该方法不支持直接对主版本config进行操作.";
            logger.error(msg);
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg(msg);
            return executeResult;
        }
        Feature existOne = this.featureRepository.findOne(feature.getId());
        if (null == existOne) {
            executeResult = new ExecuteResult();
            executeResult.setCode(StandardFeedBackInfo.REQUEST_ERROR);
            executeResult.setMsg("id指定的feature不存在 id:" + feature.getId());
            return executeResult;
        }
        final String existsReqId = existOne.getReqId();
        if ((!"-1".equals(existsReqId)) && (null != existsReqId) && (!reqId.equals(existsReqId))) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg("feature被其它req占用, reqId:" + existsReqId);
            return executeResult;
        }
        //TODO
//        IndexingId indexingIdFeatureToReq = new IndexingId("feature_req_indexing", existOne.getFeatureId());
//        Indexing featureIndexing = this.indexingService.getIndexing(indexingIdFeatureToReq);
//        if (null != featureIndexing) {
//            Map<String, String> temp = featureIndexing.getIndexMap();
//            if (!CollectionUtils.isEmpty(temp)) {
//                String otherReqId = temp.keySet().iterator().next();
//                if (!reqId.equalsIgnoreCase(otherReqId)) {
//                    executeResult.setCode(BaseController.REQUEST_ERROR);
//                    executeResult.setMsg("feature被其它req占用, reqId:" + otherReqId);
//                    return executeResult;
//                }
//            }
//        }

        String id = existOne.getId();
        FeatureReqId featureReqId = new FeatureReqId();
        featureReqId.setReqId(reqId);
        featureReqId.setFeatureId(id);
        FeatureReq featureReq = this.featureReqRepository.findOne(featureReqId);
        String configId = null == featureReq ? null : featureReq.getAttrConfigId();
        Config config = new Config();
        config.setId(configId);
        Map<String, String> attrs = feature.getAttr();
        //将feature_name放入feature变更
        //req改feature_name并不认为占用了feature
        this.featureOperations.updatePropertiesNotNullById(feature);
        if (null == attrs) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg("传入的attr为空，放弃操作");
            return executeResult;
        }
        /** attrs为空map时(且不为null)这里会重置feature的config ,解除占用关系*/
        if (CollectionUtils.isEmpty(attrs)) {
            logger.info("empty attrs found, reset(delete) will be executed.");
            if ("ADD".equalsIgnoreCase(existOne.getStatus())) {
                executeResult.setCode(BaseController.REQUEST_ERROR);
                executeResult.setMsg("指定feature为该req所创建，feature未发布前不允许解除关联");
                return executeResult;
            }
            //该功能点没有被占用，不用解除占用
            if (existsReqId == null || "-1".equals(existsReqId)) {
                return executeResult;
            }
            try {
                IndexingId indexingId = new IndexingId("req_feature_indexing", reqId);
                this.indexingService.remove(indexingId, new String[]{id});
//                this.indexingService.deleteIndex(indexingIdFeatureToReq);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                executeResult.setCode(BaseController.REQUEST_ERROR);
                executeResult.setMsg(e.getMessage());
                return executeResult;
            }
            if (!StringUtils.isEmpty(configId)) {
                this.configService.deleteConfigById(configId);
                this.featureReqRepository.delete(featureReqId);

            }
            if ((!"ADD".equalsIgnoreCase(existOne.getStatus())) && (!"ONLINE".equalsIgnoreCase(existOne.getStatus()))) { //将feature状态更新为ONLINE
                Feature update = new Feature();
                update.setId(existOne.getId());
                update.setStatus("ONLINE");
                update.setReqId("-1");
                this.featureOperations.updatePropertiesNotNullById(update);
            }
            return executeResult;
        }

        /** 以下以刷新（delete-rebuild）的方式更新feature config */
        config.setKVMap(attrs);
        config = this.configService.saveConfig(config, false);
        if (StringUtils.isEmpty(configId)) { //如果对应的featureReq不存在，则新建
            configId = config.getId();
            featureReq = new FeatureReq();
            featureReq.setId(featureReqId);
            featureReq.setAttrConfigId(configId);
            this.featureReqRepository.save(featureReq);
        }
        //刷新indexing req_feature
        IndexingId indexingId = new IndexingId("req_feature_indexing", reqId);
        Map<String, String> indexingMap = new HashMap<>();
        String featureName = feature.getFeatureName();
        indexingMap.put(id, featureName);
        try {
            this.indexingService.indexing(new Indexing(indexingId, indexingMap));
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg(e.getMessage());
            return executeResult;
        }
        if ((!"ADD".equalsIgnoreCase(existOne.getStatus()))) { //将feature状态更新为UPDATE
            Feature update = new Feature();
            update.setId(existOne.getId());
            update.setReqId(reqId);
            update.setStatus("UPDATE");
            this.featureOperations.updatePropertiesNotNullById(update);
        }

        return executeResult;
    }

/**
 public ExecuteResult deleteFeature(Feature feature) {
 ExecuteResult executeResult = new ExecuteResult();
 Feature existOne = this.featureRepository.findById(feature.getId());
 if (null == existOne) {
 executeResult.setCode(StandardFeedBackInfo.REQUEST_ERROR);
 executeResult.setMsg("指定参数未找到feature, id:" + feature.getId() + ", reqId:" + feature.getReqId());
 return executeResult;
 }
 if (!StringUtils.isEmpty(existOne.getReqId()) && !Constants.FEATURE_ROOT_REQ_ID.equals(existOne.getReqId()) && !feature.getReqId().equals(existOne.getReqId())) {
 Assert.isTrue(feature.getReqId().equals(existOne.getReqId()), "当前req不是功能点对应的req.req=" + feature.getReqId() + ".dbreq=" + existOne.getReqId());
 }
 //        this.featureOperations.updateFeature(feature);
 if ("ADD".equalsIgnoreCase(existOne.getStatus()) || Constants.FEATURE_ROOT_REQ_ID.equals(feature.getReqId())) {
 if (!Constants.FEATURE_ROOT_REQ_ID.equalsIgnoreCase(feature.getReqId())) {   //reqId != -1时
 try {
 this.flushIndexingForReqFeature(existOne, feature.getReqId(), -1);
 } catch (Exception e) {
 logger.error(e.getMessage(), e);
 executeResult.setCode(BaseController.REQUEST_ERROR);
 executeResult.setMsg(e.getMessage());
 return executeResult;
 }
 FeatureReqId featureReqId = new FeatureReqId();
 featureReqId.setFeatureId(existOne.getId());
 featureReqId.setReqId(feature.getReqId());
 FeatureReq featureReq = featureReqRepository.findOne(featureReqId);
 if (null != featureReq) {
 configService.deleteConfigById(featureReq.getAttrConfigId());
 featureReqRepository.delete(featureReqId);
 }
 }
 configService.deleteConfigById(existOne.getAttrConfigId());
 this.featureRepository.delete(existOne.getId());
 existOne.setStatus("DELETE");
 //修改父节点的children
 //            Feature parent = this.featureRepository.findByFeatureId(existOne.getParentId());
 //            if (null != parent) {
 //                parent.getChildren().remove(existOne.getFeatureId());
 //                this.featureRepository.save(parent);
 //            }
 executeResult.setData(null);
 } else {
 try {
 this.flushIndexingForReqFeature(existOne, feature.getReqId(), 1);
 } catch (Exception e) {
 logger.error(e.getMessage(), e);
 executeResult.setCode(BaseController.REQUEST_ERROR);
 executeResult.setMsg(e.getMessage());
 return executeResult;
 }
 existOne.setStatus("DELETE");
 existOne.setReqId(feature.getReqId());
 this.featureRepository.save(existOne);
 executeResult.setData(existOne);
 }


 return executeResult;
 }
 */

    /**
     * @param feature, 处理indexing表中的两组记录，req_feature_indexing
     * @param optMode  -1删除， 1-新增
     */
    private void flushIndexingForReqFeature(Feature feature, String reqId, int optMode) throws Exception {

        if (optMode == 1) {
            Indexing indexing = new Indexing();
            IndexingId indexingId = new IndexingId("req_feature_indexing", reqId);
            Map<String, String> indexMap = new HashMap<String, String>();
            indexMap.put(feature.getId(), feature.getFeatureName());
            indexing.setIndexMap(indexMap);
            indexing.setId(indexingId);
            this.indexingService.indexing(indexing);

        } else if (optMode == -1) {
            IndexingId indexingId = new IndexingId("req_feature_indexing", reqId);
            this.indexingService.removeIfExists(indexingId, new String[]{feature.getId()});
        }
        ExecuteResult executeResult = brdRequirementManager.operateRelationBetweenReqAndFeature(feature.getId(), reqId, String.valueOf(optMode));
        if (!"0".equals(executeResult.getCode())) {
            logger.error(executeResult.getDesc());
            throw new Exception(executeResult.getDesc());
        }
    }

    /**
     * 这个方法是req为-1时直接修改feature主版本
     *
     * @param feature
     * @return
     */
    public ExecuteResult updateFeature(Feature feature) {
//        ExecuteResult executeResult = this.checkUpdateFeature(feature);
        ExecuteResult executeResult = new ExecuteResult();
        Feature existOne = this.featureRepository.findById(feature.getId());
        if (existOne == null) {
            executeResult.setCode(StandardFeedBackInfo.REQUEST_ERROR);
            executeResult.setMsg("id指定的feature不存在, id:" + feature.getId() + ",reqId:" + feature.getReqId());
            return executeResult;
        }
//        if ("add".equalsIgnoreCase(existOne.getFeatureChangeType())) {    //在修改add类型的pag_layout时layoutChangeType是不会改变的
//            feature.setFeatureChangeType(null);
//        }
        if (!CollectionUtils.isEmpty(feature.getAttr())) {


            try {
                String newHistoryVersion = this.getFeatureHistoryVersion(existOne.getId());
                Config masterConfigBak = this.configService.getConfigMap(existOne.getAttrConfigId(), false);


                masterConfigBak.setId(null);
                masterConfigBak = this.configService.saveConfig(masterConfigBak);
                FeatureHistory featureHistory = new FeatureHistory();
                featureHistory.setAttrConfigId(masterConfigBak.getId());
                featureHistory.setCreateTime(new Date());
                featureHistory.setFeatureId(feature.getId());
                featureHistory.setReqId("-1");
                featureHistory.setFeatureName(feature.getFeatureName());
                featureHistory.setVersion(newHistoryVersion);
                this.featureHistoryRepository.save(featureHistory);

                feature.getAttr().put("version", FeatureVersionGenerator.getVersionNo());
                feature.getAttr().put("date", System.currentTimeMillis() + "");
                Config attrConfig = this.configService.saveConfig(existOne.getAttrConfigId(), null, feature.getAttr(), null, null);
                feature.setAttrConfigId(attrConfig.getId());
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                executeResult.setToError();
                executeResult.setMsg(e.getMessage());
                return executeResult;
            }
        }
        this.featureOperations.updatePropertiesNotNullById(feature);
        if ((!StringUtils.isEmpty(feature.getFeatureName())) || (!StringUtils.isEmpty(feature.getOriginalPageId()))) {
            Feature newOne = this.featureRepository.findById(feature.getId());
            this.pathContainer.updatePath(newOne.getId(), newOne.getOriginalPageId(), newOne.getFeatureName(), null);
        }
        executeResult.setData(feature);
        return executeResult;
    }

    private ExecuteResult checkUpdateFeature(Feature feature) {
        ExecuteResult executeResult = new ExecuteResult();
        if (null != feature.getStatus() && (!"UPDATE".equalsIgnoreCase(feature.getStatus()))) {
            executeResult.setCode(StandardFeedBackInfo.REQUEST_ERROR);
            executeResult.setMsg("非法的status type类型， （update操作）:" + feature.getStatus());
        }
        return executeResult;
    }

    /**
     * 这里的create必定存在对应的
     *
     * @param feature
     * @return
     */
//    @Deprecated
//    private ExecuteResult createFeature(Feature feature) {
//        ExecuteResult executeResult = this.checkCreateFeature(feature);
//
//        Feature master = this.featureRepository.findOne(feature.getId());
//        if (null == master) {
//            executeResult.setCode(StandardFeedBackInfo.REQUEST_ERROR);
//            executeResult.setMsg("no master feature found for id:" + feature.getId());
//            return executeResult;
//        }
//        Config featureAttr = this.configService.saveConfig(null, master.getAttrConfigId(), feature.getAttr(), null, null);
//        master.setAttrConfigId(featureAttr.getId());
//        master.setId(SeqGenerate.createId("F"));
//        master.setStatus(feature.getStatus());
//        master.setReqId(feature.getReqId());
//        this.featureRepository.save(master);
//        try {
//            this.flushIndexingForFeatureAndReq(master, feature.getReqId(), 1);
//            executeResult.setData(master);
//        } catch (Exception e) {
//            logger.error(e.getMessage(), e);
//            executeResult.setMsg(e.getMessage());
//            executeResult.setCode(StandardFeedBackInfo.REQUEST_ERROR);
//        }
//        return executeResult;
//    }
    private ExecuteResult checkCreateFeature(Feature feature) {
        ExecuteResult executeResult = new ExecuteResult();
        if (null == feature.getStatus()) {
            feature.setStatus("UPDATE");
        }
        if (!("UPDATE".equalsIgnoreCase(feature.getStatus()) || "DEL".equalsIgnoreCase(feature.getStatus()))) {
            executeResult.setCode(StandardFeedBackInfo.REQUEST_ERROR);
            executeResult.setMsg("update/delete操作遭遇非法的status:" + feature.getStatus());
        }
        return executeResult;
    }

    /**
     * 创建一个新的feature
     *
     * @param feature
     * @return
     */
    public ExecuteResult addFeature(Feature feature) {
        ExecuteResult executeResult = this.checkFeatureAdding(feature);
        if (!executeResult.isSuccess()) {
            return executeResult;
        }

        if (StringUtils.isEmpty(feature.getReqId()) || Constants.FEATURE_ROOT_REQ_ID.equals(feature.getReqId())) {
            feature.setReqId(Constants.FEATURE_ROOT_REQ_ID);
            feature.setStatus(Constants.FEATURE_STATUS_ONLINE);
        } else {
            feature.setStatus(Constants.FEATURE_STATUS_ADD);
        }
        feature.setId(SeqGenerate.createId(IdTag.FEATURE_ID));

        //TODO 不再处理path
//        if ((!StringUtils.isEmpty(feature.getFeatureName())) && StringUtils.isEmpty(feature.getPath())) {
//            //根据parent处理path
//            String path = StringUtils.isEmpty(parent.getPath()) ? "" : parent.getPath() + "/";
//            path = path + feature.getFeatureName();
//            feature.setPath(path);
//        }
        Map<String, String> configIdMap = new HashMap<>();
//        feature.getAttr().put("feature_name",feature.getFeatureName());
        try {
            //创建对应的attr_config，这个config可能是没有map的
            configIdMap = this.generateConfigForFeature(feature.getAttr(), feature.getReqId());
            feature.setAttrConfigId(configIdMap.get("master"));
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            executeResult.setCode(StandardFeedBackInfo.REQUEST_ERROR);
            executeResult.setMsg(e.getMessage());
            return executeResult;
        }
        this.featureRepository.save(feature);
        if (!Constants.FEATURE_ROOT_REQ_ID.equals(feature.getReqId())) {
            //新增req feature config 记录
            FeatureReqId featureReqId = new FeatureReqId();
            featureReqId.setReqId(feature.getReqId());
            featureReqId.setFeatureId(feature.getId());
            FeatureReq featureReq = new FeatureReq();
            featureReq.setId(featureReqId);
            featureReq.setAttrConfigId(configIdMap.get("req"));
            featureReqRepository.save(featureReq);
            //新增功能点占用关系
            try {
                this.flushIndexingForReqFeature(feature, feature.getReqId(), 1);
            } catch (Exception e) {
                logger.error("com.winit.feature.manager.FeatureManager.addFeature 修改功能点占用异常", e);
            }
        }

        executeResult.setData(feature);
        return executeResult;
    }

    /**
     * 新增功能点时 创建两个config map
     *
     * @param changeConfig
     * @return
     * @throws Exception
     */
    private Map generateConfigForFeature(Map<String, String> changeConfig, String reqId) throws Exception {
        Map map = new HashMap();
        Config attrConfig = new Config();
        attrConfig.setKVMap(new HashMap<String, String>());
        if (!CollectionUtils.isEmpty(changeConfig)) {
            attrConfig.getKVMap().putAll(changeConfig);
        }
        Config newAttrConfig = this.configService.saveConfig(attrConfig);
        map.put("master", newAttrConfig.getId());
        if (!Constants.FEATURE_ROOT_REQ_ID.equals(reqId)) {
            attrConfig.setParentId(newAttrConfig.getId());
            Config reqConfig = this.configService.saveConfig(attrConfig);
            map.put("req", reqConfig.getId());
        }
        return map;
    }

//    private void addFeatureChilds(Feature parent, String featureId, int location) {
//        List<String> layoutChildren = parent.getChildren();
//        if (null == layoutChildren) {
//            layoutChildren = new ArrayList<>();
//            parent.setChildren(layoutChildren);
//            layoutChildren.add(featureId);
//        } else {
//            layoutChildren.add(featureId);
//        }
//    }

    private ExecuteResult checkFeatureAdding(Feature feature) {
        ExecuteResult executeResult = new ExecuteResult();
//        if (feature.getId() == null && feature.getLocationInParent() == null) {
//            executeResult.setCode(StandardFeedBackInfo.REQUEST_ERROR);
//            executeResult.setMsg("locationInParent不能为null");
//        }
        if (null != feature.getStatus() && (!"ADD".equalsIgnoreCase(feature.getStatus()))) {
            executeResult.setCode(StandardFeedBackInfo.REQUEST_ERROR);
            executeResult.setMsg("add操作遭遇非法status" + feature.getStatus());
        }
//        if (null == feature.getParentId()) {
//            executeResult.setCode(StandardFeedBackInfo.REQUEST_ERROR);
//            executeResult.setMsg("add操作缺少parentId");
//        }
        return executeResult;
    }


    //判断功能点是否被req占用，如果被占用，返回哪个reqid
    private String getFeatureStatus(String featureId, String reqId, List<Indexing> list) {
        if (list.size() == 0) {
            return null;
        }
        String status = null;
        for (Indexing index : list) {
            if (index.getId().getFilterTag().equalsIgnoreCase(featureId)) {
                if (index.getIndexMap().containsKey(reqId)) {
                    status = "self-relate";
                } else {
                    status = "other-relate";
                }
                break;
            }
        }
        return status;
    }

    /**
     * 取出feature的config attr，对于feature不再做合并
     *
     * @param feature
     * @param reqId
     * @throws Exception
     */
    private void featureAutoConfigure(Feature feature, String reqId) throws Exception {
        if (StringUtils.isEmpty(reqId) || "-1".equalsIgnoreCase(reqId)) {
            Map<String, String> attr = null;
            String attrConfigId = feature.getAttrConfigId();
            if (!StringUtils.isEmpty(attrConfigId)) {
                Config attrConfig = this.configService.getConfigMap(attrConfigId, false);
                if (null != attrConfig) {
                    attr = attrConfig.getKVMap();
                }
            }
            feature.setAttr(attr);
            return;
        }
        FeatureReqId id = new FeatureReqId();
        id.setFeatureId(feature.getId());
        id.setReqId(reqId);
        FeatureReq featureReq = this.featureReqRepository.findOne(id);
        if (null != featureReq) {
            String configId = featureReq.getAttrConfigId();
            if (!StringUtils.isEmpty(configId)) {
                Config reqAttrConfig = this.configService.getConfigMap(configId, false);
                if (reqAttrConfig != null) {
                    Map<String, String> temp = reqAttrConfig.getKVMap();
                    feature.setAttr(temp);
                }
            }
        }
//        if (!CollectionUtils.isEmpty(attr)) {
////            feature.setFeatureName(attr.get("feature_name"));
//        }
//        feature.setAttr(attr);
    }

    public ExecuteResult operateFeaturesForReqOnline(List<String> reqIds, String reqName) {
        ExecuteResult rs = null;

        for (String reqId : reqIds) {

            rs = this.operateFeaturesForReqOnline(reqId, reqName);
            if (!rs.isSuccess()) {
                return rs;
            }
        }
        return rs;
    }

    private String getReqName(String reqId) throws Exception {
        String reqName = null;

        List<?> rs = this.brdRequirementManager.getBrdRequirements(null, null, reqId, null, null, null, null, true,null,true);

        if(rs.size() > 0){
            BrdRequirement brdRequirement =(BrdRequirement) rs.get(0);
//            System.out.println(test.getReqName());
//            reqName = ((JSONObject) rs.get(0)).getString("reqName");
            reqName=brdRequirement.getReqName();
        }
        return reqName;
    }

    public ExecuteResult operateFeaturesForReqOnline(String reqId, String reqName) {
        ExecuteResult rs = new ExecuteResult();
        IndexingId indexingId = new IndexingId("req_feature_indexing", reqId);
        Indexing indexing = this.indexingService.getIndexing(indexingId);
        if (null == indexing) {
            rs = ExecuteResult.successExecuteResult(Object.class);
            return rs;
        }
        Map<String, String> relateFeatures = indexing.getIndexMap();
        if (CollectionUtils.isEmpty(relateFeatures)) {
            rs = ExecuteResult.successExecuteResult(Object.class);
            return rs;
        }
        try {
            if (StringUtils.isEmpty(reqName)) {
                reqName = this.getReqName(reqId);
            }
        } catch (Exception e) {
            logger.error("获取reqName失败");
            logger.error(e.getMessage(), e);
            rs.setToError();
            rs.setMsg(e.getMessage());
            return rs;
        }
        for (String id : relateFeatures.keySet()) {
            try {
                rs = this.operateFeatureForReqOnline(id, reqId, reqName);
                if (!rs.isSuccess()) {
                    return rs;
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                rs.setCode(BaseController.REQUEST_ERROR);
                rs.setMsg(e.getMessage());
                return rs;
            }
        }
        return rs;
    }

    private ExecuteResult operateFeatureForReqOnline(String id, String reqId, String reqName) throws Exception {
        ExecuteResult executeResult = new ExecuteResult();
        Feature feature = this.featureRepository.findByFeatureId(id);
        if (null == feature || feature.getReqId() == null) {    //处理脏数据或者数据不致
            return executeResult;
        }

//        if ((!reqId.equalsIgnoreCase(feature.getReqId())) && (null != feature.getReqId()) && (!"-1".equalsIgnoreCase(feature.getReqId()))) {
////            String msg = "data error between req_feature_indexing and feature, reqId" + reqId;
//            String msg = "数据错误, feature中的reqId与indexing中的req_feature_indexing中的记录不匹配" + reqId;
//            logger.error(msg);
//            executeResult.setCode(BaseController.REQUEST_ERROR);
//            executeResult.setMsg(msg);
//            return executeResult;
//        }
        /** 判断版本冲突 */
        Config masterConfig = this.configService.getConfigMap(feature.getAttrConfigId(), false);
        Map<String, String> masterConfigMap = masterConfig.getKVMap();
        String masterVersion = masterConfigMap.get("version");
        FeatureReq featureReq = this.featureReqRepository.findOne(new FeatureReqId(id, reqId));
        if (null == featureReq || StringUtils.isEmpty(featureReq.getAttrConfigId())) {
            return executeResult;
        }
        Config reqConfig = this.configService.getConfigMap(featureReq.getAttrConfigId(), false);
        Map<String, String> reqConfigMap = reqConfig.getKVMap();
        String reqRefMasterVersion = reqConfigMap.get("master_version");
        if ((masterVersion != null) && (!masterVersion.equals(reqRefMasterVersion))) {   //版本冲突
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg("feature config版本冲突,feature_name:" + feature.getFeatureName() + ",master_version:" + masterVersion + ", req_ref_master_version:" + reqRefMasterVersion + ", req_snapshot of master:" + masterConfigMap.get("req_snapshot"));
            return executeResult;
        }

        /** 17-12-20新版本不再有delete状态，对于req删除feature时都直接删除了 */
        if ("DEL".equalsIgnoreCase(feature.getStatus()) && reqId.equalsIgnoreCase(feature.getReqId())) { //标记删除的直接删除
            this.featureRepository.delete(id);
//            this.indexingService.deleteIndex(new IndexingId("feature_req_indexing", featureId));
            return executeResult;
        }
//        FeatureReqId featureReqId = new FeatureReqId(id, reqId);

        /** 合并feature config */
//        FeatureReq featureReq = this.featureReqRepository.findOne(featureReqId);
        if (null != featureReq) {
            /* 合并feature上线上时持feature历史版本记录，2018-01-10 */
            String newHistoryVersion = this.getFeatureHistoryVersion(id);
            Config masterConfigBak = this.configService.getConfigMap(feature.getAttrConfigId(), false);

            String oldPrototypeFilePath = masterConfigBak.getKVMap().get("prototype_file_path");
            if (!StringUtils.isEmpty(oldPrototypeFilePath)) {
                String newPrototypeFilePath = this.copyPrototypeFileForNewVersion(oldPrototypeFilePath, newHistoryVersion);
                if (!StringUtils.isEmpty(newPrototypeFilePath)) {
                    masterConfigBak.getKVMap().put("prototype_file_path", newPrototypeFilePath);
                }
            }

            masterConfigBak.setId(null);
            masterConfigBak = this.configService.saveConfig(masterConfigBak);
            FeatureHistory featureHistory = new FeatureHistory();
            featureHistory.setAttrConfigId(masterConfigBak.getId());
            featureHistory.setCreateTime(new Date());
            featureHistory.setFeatureId(id);
            featureHistory.setReqId(reqId);
            featureHistory.setFeatureName(feature.getFeatureName());
            featureHistory.setVersion(newHistoryVersion);
            this.featureHistoryRepository.save(featureHistory);

            String featureConfigId = featureReq.getAttrConfigId();

            this.configService.mergeConfigById(featureConfigId, feature.getAttrConfigId(), true);
//            Indexing reqFeatureIndexing = this.indexingService.getIndexing(new IndexingId("req_feature_indexing", reqId));
            /**更新version信息*/
            //TODO reqName
            masterConfig = this.configService.getConfigMap(feature.getAttrConfigId(), false);
            String newMasterVersion = FeatureVersionGenerator.getVersionNo();
            this.updateVersionInfoForFeature(masterConfig.getKVMap(), newMasterVersion, "", reqId);
            String time = System.currentTimeMillis() + "";
            masterConfig.getKVMap().put("date", time);

            Config featureConfig = this.configService.getConfigMap(featureConfigId, true);
            String featureOldPrototypeFilePath = featureConfig.getKVMap().get("prototype_file_path");
            if ((!StringUtils.isEmpty(featureOldPrototypeFilePath)) && (!featureOldPrototypeFilePath.equalsIgnoreCase(oldPrototypeFilePath))) {
                String masterPrototypePath = PROTOTYPE_PATH + feature.getId() + File.separator + "master" + File.separator + "online" + File.separator;
                String command = "rm -rf " + masterPrototypePath;
                logger.info("command for delete prototype file when operate on req online, command:" + command);
                Runtime.getRuntime().exec(command).waitFor();
                String reqPrototypeFilePath = PROTOTYPE_PATH + featureOldPrototypeFilePath.substring(1);
                if (new File(reqPrototypeFilePath).exists()) {
                    command = "cp -r " + reqPrototypeFilePath + " " + masterPrototypePath;
                    File masterDir = new File(masterPrototypePath);
                    if (!masterDir.exists()) {
                        masterDir.getParentFile().mkdirs();
                    }
                    logger.info("command for cp prototype file when operate on req online, command:" + command);
                    Runtime.getRuntime().exec(command).waitFor();
                    masterConfig.getKVMap().put("prototype_file_path", File.separator + feature.getId() + File.separator + "master" + File.separator + "online" + File.separator);
                }
            }

            this.configService.saveConfig(masterConfig);
            this.updateVersionInfoForFeature(reqConfigMap, null, newMasterVersion, reqId);
            reqConfigMap.put("to_master_version", newMasterVersion);
            reqConfigMap.put("date", time);
            this.configService.saveConfig(reqConfig);
            this.submit(reqId, id, reqName, null);
        }
        //将page与feature中的关系feature_page_indexing/page_feature_indexing中的req全改为-1
        IndexingId featurePageIndexingId = new IndexingId("feature_page_indexing", id);
        Indexing featurePageIndexing = this.indexingService.getIndexing(featurePageIndexingId);
        if (featurePageIndexing != null) {
            Map<String, String> indexMap = featurePageIndexing.getIndexMap();
            if (!CollectionUtils.isEmpty(indexMap)) {
                boolean pageFeatureExists = false;
                for (Map.Entry<String, String> entry : indexMap.entrySet()) {
                    if (reqId.equals(entry.getValue())) {
                        pageFeatureExists = true;
                        entry.setValue("-1");
                        Map<String, String> pageFeatureIndexingMap = new HashMap<>();
                        pageFeatureIndexingMap.put(id, "-1");
                        this.indexingService.indexing(new Indexing(new IndexingId("page_feature_indexing", entry.getKey()), pageFeatureIndexingMap));
                    }
                }
                if (pageFeatureExists) {
                    this.indexingService.indexing(featurePageIndexing);
                }
            }
        }
        this.reflushFeatureReqIndexing(id, reqId, -1);
//        this.indexingService.deleteIndex(new IndexingId("feature_req_indexing", id));
        Feature update = new Feature();
        update.setId(feature.getId());
        Indexing featureReqIndexing = this.indexingService.getIndexing(new IndexingId("feature_req_indexing", id));
        if (null == featureReqIndexing || CollectionUtils.isEmpty(featureReqIndexing.getIndexMap())) {
//            update.setReqId("-1");
            update.setStatus("ONLINE");
        } else {
            update.setStatus("UPDATE");
        }
        this.featureOperations.updatePropertiesNotNullById(update);
        return executeResult;
    }

    private String getFeatureHistoryVersion(String featureId) {
        FeatureHistory featureHistory = this.featureHistoryRepository.findLatestVersionByFeatureId(featureId);
        if (null == featureHistory) {
            return "V1.0";
        }
        String curVersion = featureHistory.getVersion();
        int splitLoc = curVersion.indexOf(".");
        String prefix = curVersion.substring(0, splitLoc);
        String suffix = curVersion.substring(splitLoc + 1);
        suffix = (Integer.valueOf(suffix) + 1) + "";
        return prefix + "." + suffix;
    }

    /**
     * 解除关联后重置功能点信息
     *
     * @param featureId
     * @return
     */
    public Map initFeature(String featureId) {
        Map map = new HashMap<>();
        if (StringUtils.isEmpty(featureId)) {
            logger.info("com.winit.feature.manager.FeatureManager.initFeature featureId为空");
            map.put("code", "1");
            map.put("desc", "重置功能点信息,功能点id为空");
            return map;
        }

        Feature feature = featureRepository.findByFeatureId(featureId);
        if (null == feature) {
            logger.info("com.winit.feature.manager.FeatureManager.initFeature feature为null featureId=" + featureId);
            map.put("code", "1");
            map.put("desc", "重置功能点信息,根据功能点id查询功能点为空");
            return map;
        }

        if (Constants.FEATURE_ROOT_REQ_ID.equals(feature.getReqId())) {
            logger.info("com.winit.feature.manager.FeatureManager.initFeature feature当前为线上版本,不需要解除关联 featureId=" + featureId);
            map.put("code", "1");
            map.put("desc", "重置功能点信息,当前功能点为线上版本,不需要解除关联");
            return map;
        }
        map.put("code", "0");
        map.put("desc", "");
        // 2017-12-07新增对indexing表中req->feature关系的处理
        try {
            this.flushIndexingForReqFeature(feature, feature.getReqId(), -1);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            map.put("code", "1");
            map.put("desc", "数据错误，indexing中feature的关联关系错误");
            return map;
        }
//        IndexingId indexingId = null;
//        try {
//            indexingId = new IndexingId("req_feature_indexing", feature.getReqId());
//            if(this.indexingService.getIndexing(indexingId) != null) {
//                this.indexingService.remove(indexingId, new String[]{featureId});
//            }
//        } catch (Exception e) {
//            logger.error(e.getMessage(), e);
//            map.put("code","0");
//            map.put("desc", "数据错误，indexing中feature的关联关系错误");
//            return map;
//        }
//        indexingId = new IndexingId("feature_req_indexing", featureId);
//        this.indexingService.deleteIndex(indexingId);


        Map<String, Boolean> data = new HashMap<>();
        //删除req和功能点关联关系
        FeatureReqId featureReqId = new FeatureReqId();
        featureReqId.setFeatureId(featureId);
        featureReqId.setReqId(feature.getReqId());
        FeatureReq featureReq = featureReqRepository.findOne(featureReqId);
        if (null != featureReq) {

            featureReqRepository.delete(featureReq);
            //删除req修改功能点信息config
            configService.deleteConfigById(featureReq.getAttrConfigId());
        }


        //修改功能点信息 如果功能点为新增功能点，则直接删除，否则只是修改功能点的状态
        if (Constants.FEATURE_STATUS_ADD.equals(feature.getStatus())) {
            featureRepository.delete(feature);
            data.put("isDel", true);
        } else {
            feature.setStatus(Constants.FEATURE_STATUS_ONLINE);
            feature.setReqId(Constants.FEATURE_ROOT_REQ_ID);
            featureRepository.save(feature);
            data.put("isDel", false);
        }
        map.put("data", data);
        return map;
    }

    /**
     * 根据reqid查询功能点信息列表
     * 使用req的index,先查询req关联了哪些feature
     * 然后再根据featureid去查列表
     *
     * @param reqId
     * @return
     */
    public List<Feature> getAllFeatureForReq(String reqId,String withAttr) {
        List<Feature> list = new ArrayList<>();
        String featureIdsStr = null;
        try {
            featureIdsStr = brdRequirementManager.getReqFeatureIds(reqId);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return list;
        }
        if (!StringUtils.isEmpty(featureIdsStr)) {
            list = this.featureRepository.findByFeatureIds(Arrays.asList(featureIdsStr.split(",")));
            if (null == list) {
                list = new ArrayList<>();
            }
        } else { //兼容老旧数据，在product brd_requirement表中没有features记录;
            //1、查询req的index
            IndexingId indexingId = new IndexingId(Constants.REQ_FEATURE_INDEX_GROUP, reqId);
            Indexing index = this.indexingService.getIndexing(indexingId);
            if (null == index) {
                return new ArrayList<>();
            }
            Set<String> set = index.getIndexMap().keySet();
            List<String> ids = new ArrayList<>();
            ids.addAll(set);
            list = this.featureRepository.findByFeatureIds(ids);
            if (null == list) {
                list = new ArrayList<>();
            }
            logger.info("com.winit.feature.manager.FeatureManager.getAllFeatureForReq reqId=" + reqId + ",list.size=" + list.size());
        }
        if (!CollectionUtils.isEmpty(list)) {
            for (Feature feature : list) {
                feature.setPath(this.pathContainer.getPathById(feature.getId(), false));
            }
        }
        if ("1".equals(withAttr)) {
            for (Feature feature : list) {
                try {
                    this.featureAutoConfigure(feature, reqId);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
        return list;
    }

    public void createPrototypeForPage(Page page) {
        String pageId = page.getId();
        String path = page.getMenuPath();
        Feature feature = new Feature();
        feature.setId("PROTOTYPE" + pageId);
        feature.setFeatureName("页面");
        feature.setOriginalPageId(pageId);
        feature.setType("PROTOTYPE");
        feature.setPath(path + "/" + page.getTitle());
        feature.setReqId("-1");
        feature.setStatus("ONLINE");
        feature.setFeatureKind(FeatureKinds.UI.toString());
        feature.setSys(this.menuService.getMenuById(page.getMenuId()).getSys().toUpperCase());
        Config config = new Config();
        Map<String, String> configMap = new HashMap<>();
        configMap.put("prototype", "");
        this.updateVersionInfoForFeature(configMap, FeatureVersionGenerator.getVersionNo(), "", "");
        config.setKVMap(configMap);
        config = this.configService.saveConfig(config);
        feature.setAttrConfigId(config.getId());
        this.featureRepository.save(feature);
        this.relateToPage("-1", feature.getId(), pageId);
        this.pathContainer.add(feature.getId(), pageId, feature.getFeatureName(), null);
    }

    private void updateVersionInfoForFeature(Map<String, String> configMap, String version, String masterVersion, String reqSnapshot) {
        if (null != version) {
            configMap.put("version", version);
        }
        if (null != masterVersion) {
            configMap.put("master_version", masterVersion);
        }
        if (null != reqSnapshot) {
            configMap.put("req_snapshot", reqSnapshot);
        }
    }

    public List<FeatureHistory> getFeatureHistory(String featureId, String reqId) {
        if (null == reqId) {
            return this.featureHistoryRepository.findByFeatureId(featureId);
        } else {
            return this.featureHistoryRepository.findByFeatureIdAndReqId(featureId, reqId);
        }
    }


    public ExecuteResult submit(String reqId, String featureId, String reqName, String newVersionLabel) throws Exception {
        ExecuteResult executeResult = new ExecuteResult();
        FeatureReq featureReq = this.featureReqRepository.findOne(new FeatureReqId(featureId, reqId));
        if (null == featureReq || StringUtils.isEmpty(featureReq.getAttrConfigId())) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg("不存在req对应的feature");
            return executeResult;
        }
        String reqConfigId = featureReq.getAttrConfigId();
        Config reqConfigBak = this.configService.getConfigMap(reqConfigId, true);
        Config reqConfig = this.configService.getConfigMap(reqConfigId, true);
        if (reqConfig.getKVMap().get("date") == null) {
            reqConfig.getKVMap().put("date", System.currentTimeMillis() + "");
            this.configService.saveConfig(reqConfig);
        }

        VersionHistory newVersion = new VersionHistory();
        newVersion.setCreateTime(new Date());

        newVersion.setRelationId(featureId);
        newVersion.setReqId(reqId);
        newVersion.setRelationName(this.featureRepository.findOne(featureId).getFeatureName());
//        reqName = StringUtils.isEmpty(reqName) ? "UNKNOW" : reqName;
        if (StringUtils.isEmpty(reqName)) {
            reqName = this.getReqName(reqId);
        }
        newVersion.setReqName(reqName);
        newVersion.setType("REQ_FEATURE");

//        String version = null;
        if (null == newVersionLabel) {
            VersionHistory topVersionHistory = this.versionHistoryRepository.findFirstByTypeAndReqIdAndRelationIdOrderByCreateTimeDesc("REQ_FEATURE", reqId, featureId);
            if (null == topVersionHistory) {
                newVersionLabel = "v1.1.1";
            } else {
                newVersionLabel = this.getVersionOfVersionHistoryForReqVersion(topVersionHistory.getVersion());
            }
        }
        newVersion.setVersion(newVersionLabel);


        String prototypeFilePath = reqConfigBak.getKVMap().get("prototype_file_path");
        if (!StringUtils.isEmpty(prototypeFilePath)) {
            String temp = prototypeFilePath.startsWith(File.separator) ? prototypeFilePath.substring(1) : prototypeFilePath;
            String prototypeFile = PROTOTYPE_PATH + temp;
            File file = new File(prototypeFile);
            if (file.exists()) {
                File fileBak = null;
                String prototypeFilePathBak = null;
                if (prototypeFile.indexOf(File.separator + "master" + File.separator) >= 0 && (!"-1".equals(reqId))) {
                    String newPrototypeFileDir = prototypeFile.replace(File.separator + "master" + File.separator, File.separator + reqId + File.separator);
                    fileBak = new File(newPrototypeFileDir);
                    prototypeFilePathBak = prototypeFilePath.replace(File.separator + "master", File.separator + reqId);
                } else {
                    fileBak = file;
                    prototypeFilePathBak = prototypeFilePath;
                }
                String parentPathBak = fileBak.getParent();
                String prototyePathBak = parentPathBak.endsWith(File.separator) ? parentPathBak + newVersionLabel : parentPathBak + File.separator + newVersionLabel + File.separator;
                String cleanCommand = "rm -rf " + prototyePathBak;
                logger.info("execute clean  command for copy prototype file, command:" + cleanCommand);
                Runtime.getRuntime().exec(cleanCommand).waitFor();

                File bakDir = new File(prototyePathBak);
                bakDir.getParentFile().mkdirs();

                String command = "cp -r " + prototypeFile + " " + prototyePathBak;
                logger.info("execute command for copy prototype file, command:" + command);
                Runtime.getRuntime().exec(command).waitFor();

                String tempPath = prototypeFilePathBak.endsWith(File.separator) ? prototypeFilePathBak.substring(0, prototypeFilePathBak.lastIndexOf(File.separator)) : prototypeFilePathBak;
                tempPath = tempPath.substring(0, tempPath.lastIndexOf(File.separator));
                tempPath = tempPath.endsWith(File.separator) ? tempPath : tempPath + File.separator;
                String newPrototypeFilePath = tempPath + newVersionLabel + File.separator;
                reqConfigBak.getKVMap().put("prototype_file_path", newPrototypeFilePath);
            }
//                String newPrototypeFilePath = this.copyPrototypeFileForNewVersion(prototypeFilePath, newVersionLabel);
        }
//        }


        reqConfigBak.setId(null);
        Config newConfig = this.configService.saveConfig(reqConfigBak);
        newVersion.setAttrConfigId(newConfig.getId());
        this.versionHistoryRepository.save(newVersion);
        return executeResult;
    }

    private String copyPrototypeFileForNewVersion(String oldPrototypeFilePath, String newVersion) throws Exception {
        String temp = oldPrototypeFilePath.startsWith(File.separator) ? oldPrototypeFilePath.substring(1) : oldPrototypeFilePath;
        String prototypeFile = PROTOTYPE_PATH + temp;
        File file = new File(prototypeFile);
        if (file.exists()) {

            String parentPath = file.getParent();
            String newPrototypeFile = parentPath.endsWith(File.separator) ? parentPath + newVersion : parentPath + File.separator + newVersion + File.separator;
            File newDir = new File(newPrototypeFile);
            if (!newDir.exists()) {
                newDir.getParentFile().mkdirs();
            }
            String command = "cp -r " + prototypeFile + " " + newPrototypeFile;
            logger.info("execute command for copy prototype file, command:" + command);
            Runtime.getRuntime().exec(command).waitFor();

            String tempPath = oldPrototypeFilePath.endsWith(File.separator) ? oldPrototypeFilePath.substring(0, oldPrototypeFilePath.lastIndexOf(File.separator)) : oldPrototypeFilePath;
            tempPath = tempPath.substring(0, tempPath.lastIndexOf(File.separator));
            tempPath = tempPath.endsWith(File.separator) ? tempPath : tempPath + File.separator;
            String newPrototypeFilePath = tempPath + newVersion + File.separator;
            return newPrototypeFilePath;
        }
        return null;
    }


    private static String getVersionOfVersionHistoryForReqVersion(String oldVersion) {
        if (StringUtils.isEmpty(oldVersion)) {
            return "v1.1.1";
        }
        String version = "v";
        oldVersion = oldVersion.substring(1);
        oldVersion = oldVersion.replaceAll("\\.", "");
        Integer intVersion = Integer.valueOf(oldVersion) + 1;
        for (char ch : intVersion.toString().toCharArray()) {
            version = version + ch + ".";
        }
        version = version.substring(0, version.length() - 1);
        return version;
    }


    public Map<String, Object> getSubmitHistory(String featureId, String reqId) {
        Map<String, Object> rs = new LinkedHashMap<>();
        if (!StringUtils.isEmpty(reqId)) {

            rs.put(reqId, this.getVersionHistories(featureId, reqId));
            return rs;
        }
        //到这里查询所有未上线的req的submit history
        Indexing featureReqIndexing = this.indexingService.getIndexing(new IndexingId("feature_req_indexing", featureId));
        if (featureReqIndexing == null || CollectionUtils.isEmpty(featureReqIndexing.getIndexMap())) {
            return rs;
        }
        Map<String, String> indexMap = featureReqIndexing.getIndexMap();
        for (Map.Entry<String, String> entry : indexMap.entrySet()) {
            String req = entry.getKey();
            rs.put(req, this.getVersionHistories(featureId, req));
        }
        return rs;
    }

    private List<VersionHistory> getVersionHistories(String featureId, String reqId) {
        List<VersionHistory> versionHistories = this.versionHistoryRepository.findByReqIdAndRelationIdAndType(reqId, featureId, "REQ_FEATURE");
        //兼容前端null报错问题
        versionHistories = null == versionHistories ? new ArrayList<VersionHistory>() : versionHistories;
        return versionHistories;
    }

    public ExecuteResult getLatestSubmitFeature(String featureId, String reqId) {
        ExecuteResult executeResult = new ExecuteResult();
        try {
            executeResult.setData(this.getLatestSubmitFeatureById(featureId, reqId));
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setMsg("查询config出错");
            return executeResult;
        }
        return executeResult;
    }

    private Feature getLatestSubmitFeatureById(String featureId, String reqId) throws Exception {
        VersionHistory topVersionHistory = this.versionHistoryRepository.findFirstByTypeAndReqIdAndRelationIdOrderByCreateTimeDesc("REQ_FEATURE", reqId, featureId);
        if (null == topVersionHistory) {
            return null;
        }
        Feature feature = this.featureRepository.findOne(featureId);
        if (null == feature) {
            return null;
        }
        Config config = this.configService.getConfigMap(topVersionHistory.getAttrConfigId(), true);
        feature.setAttr(config.getKVMap());
        feature.setPath(this.pathContainer.getPathById(feature.getId(), false));
        return feature;
    }

    public List<Feature> getReqLatestSubmitFeatures(String reqId) throws Exception {
        List<Feature> features = new ArrayList<>();
        ReqHistory reqHistory = this.brdRequirementManager.getLatestReqSubmitHistory(reqId);
        if (null == reqHistory) {
            return features;
        }
        String featureIds = reqHistory.getFeatures();
        if (StringUtils.isEmpty(featureIds)) {
            return features;
        }
        Feature temp = null;
        for (String featureId : featureIds.split(",")) {
            temp = this.getLatestSubmitFeatureById(featureId, reqId);
            if (null != temp) {
                features.add(temp);
            }
        }
        return features;
    }


    public ExecuteResult uploadPrototype(MultipartFile multipartFile, String reqId, String featureId, String version) {
        logger.info("uploadPrototype, reqId:" + reqId);
        ExecuteResult executeResult = new ExecuteResult();
        String fileName = "html.zip";
//        String attachmentId = TableIdUtil.createAttachmentId();

        boolean master = "-1".equals(reqId);
        String reqPath = master ? "master" : reqId;
        String versionPath = (!StringUtils.isEmpty(version)) ? version : master ? "online" : "temp";

        String sDir = featureId + File.separator + reqPath + File.separator + versionPath + File.separator;
        String prototypeDir = PROTOTYPE_PATH + sDir;
//        String basePath = this.getStoragePath(resourceType);
//        File directory = new File(prototypeDir);
//        if (!directory.exists()) {
//            directory.mkdirs();
//        }
        String folder = System.getProperty("java.io.tmpdir");
        File directory = new File(folder);
        File zipFile = new File(prototypeDir, fileName);


        try {
            if (zipFile.exists()) {
                zipFile.delete();
            }

            File unzipDir = new File(prototypeDir);
            if (unzipDir.exists()) {
                Runtime.getRuntime().exec("rm -rf " + prototypeDir).waitFor();
            }
            //创建文件夹
            unzipDir.mkdirs();

            zipFile.createNewFile();
            multipartFile.transferTo(zipFile);
//            executeResult = unzipFile(prototypeDir, zipFile, false);
            String command = "unzip " + zipFile.getAbsolutePath() + " -d " + prototypeDir;
            logger.info("execute command for upload prototype(start):" + command);
            Process process = Runtime.getRuntime().exec(command);
            process.waitFor();
            BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream(), "utf-8"));
            StringBuilder result = new StringBuilder();
            String line = null;
            while ((line = in.readLine()) != null) {
                result.append(line).append('\n');
            }
            logger.info("execute command for upload prototype(result):" + command + "," + result.toString());
//            zipFile.delete();
            if (master) {
                Feature feature = this.featureRepository.findOne(featureId);
                if (null != feature) {//兼容测试，执行该步骤时一定不为null
                    Config config = this.configService.getConfigMap(feature.getAttrConfigId(), true);
                    config.getKVMap().put("prototype_file_path", File.separator + sDir);
                    config.getKVMap().put("patternType", "axure");
                    this.configService.saveConfig(config);
                }
            } else {
                FeatureReq featureReq = this.featureReqRepository.findOne(new FeatureReqId(featureId, reqId));
                if (null != featureReq) { //兼容测试，执行该步骤时一定不为null
                    Config config = this.configService.getConfigMap(featureReq.getAttrConfigId(), true);
                    config.getKVMap().put("prototype_file_path", File.separator + sDir);
                    config.getKVMap().put("patternType", "axure");
                    this.configService.saveConfig(config);
                }
            }
            executeResult.setData(File.separator + sDir);
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            executeResult.setToError();
            executeResult.setMsg(e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            executeResult.setToError();
            executeResult.setMsg(e.getMessage());
        }
        return executeResult;
    }

    public File getPrototype(String reqId, String featureId, String version) {
        logger.info("uploadPrototype, reqId:" + reqId);
        boolean master = "-1".equals(reqId);
        String reqPath = master ? "master" : reqId;
        String versionPath = (!StringUtils.isEmpty(version)) ? version : master ? "online" : "temp";

        String sDir = featureId + File.separator + reqPath + File.separator + versionPath + File.separator;
        String prototypeDir = PROTOTYPE_PATH + sDir;

        File file = new File(prototypeDir + "html.zip");

        return file;
    }

    @Cacheable(cacheNames = {"getAllElements"}, key = "#sys  + '-' +  #setPath")
    public ExecuteResult getAllElements(String sys, boolean setPath) {
        ExecuteResult executeResult = new ExecuteResult();
        List<MatrixMenu> menus = this.menuService.getAllMenuBySys(sys);
//        List<MatrixMenu> matrixMenus = new LinkedList<>();
        List<Page> pages = new LinkedList<>();
        this.getMenuAndPageContainer(menus, pages, setPath);
        List<Feature> features = this.featureRepository.findBySys(sys);

        Map<String, List<Feature>> map = new HashMap<>();

        if (CollectionUtils.isEmpty(features)) {
            features = new LinkedList<>();
        } else {
            for (Feature feature : features) {
                feature.setParent_id(feature.getOriginalPageId());
                if (setPath) {
                    feature.setPath(this.pathContainer.getPathById(feature.getId(), false));
                }
                if (map.containsKey(feature.getParent_id())) {
                    map.get(feature.getParent_id()).add(feature);
                } else {
                    List<Feature> l = new ArrayList<>();
                    l.add(feature);
                    map.put(feature.getParent_id(), l);
                }
            }
        }
        Map<String, Object> data = new HashMap<>();
        data.put("menus", menus);
        data.put("pages", pages);
        data.put("features", sortFeature(map));
        executeResult.setData(data);
        return executeResult;
    }

    private List<Feature> sortFeature(List<Feature> list) {
        Map<String, List<Feature>> map = new HashMap<>();
        for (Feature feature : list) {
            if (null != this.pathContainer.getNodeInfo(feature.getOriginalPageId())) {
                if (map.containsKey(feature.getOriginalPageId())) {
                    map.get(feature.getOriginalPageId()).add(feature);
                } else {
                    List<Feature> l = new ArrayList<>();
                    l.add(feature);
                    map.put(feature.getOriginalPageId(), l);
                }
            }
        }
        return sortFeature(map);
    }

    private List<Feature> sortFeature(Map<String, List<Feature>> map) {
        List<Feature> rtnL = new ArrayList<>();
        for (String key : map.keySet()) {
            Collections.sort(map.get(key), new Comparator<Feature>() {
                @Override
                public int compare(Feature m1, Feature m2) {
                    if(m1.getId().contains("PROTOTYPE")){
                        return -1;
                    }
                    if(m2.getId().contains("PROTOTYPE")){
                        return 1;
                    }
                    String pid = m1.getOriginalPageId();
                    List<String> list = pathContainer.getChild(pid);
                    int a = list.indexOf(m1.getId());
                    int b = list.indexOf(m2.getId());
                    return a - b;
                }
            });
            rtnL.addAll(map.get(key));
        }
        return rtnL;
    }


    private void getMenuAndPageContainer(List<MatrixMenu> matrixMenuContainer, List<Page> pageContainer, boolean setPath) {
        if (CollectionUtils.isEmpty(matrixMenuContainer)) {
            return;
        }
        for (MatrixMenu matrixMenu : matrixMenuContainer) {
//            matrixMenu.setId();
//            if ("3".equals(matrixMenu.getLevel())) { //3级menu直接获取page
            List<Page> pages = this.pageService.getPagesForMenuId(matrixMenu.getId(), setPath);
            if (!CollectionUtils.isEmpty(pages)) {
                //排序page
                Collections.sort(pages, new Comparator<Page>() {
                    @Override
                    public int compare(Page m1, Page m2) {
                        String pid = m1.getMenuId();
                        List<String> list = pathContainer.getChild(pid);
                        int a = list.indexOf(m1.getId());
                        int b = list.indexOf(m2.getId());
                        return a - b;
                    }
                });
                for (Page page : pages) {
                    page.setParent_id(page.getMenuId());
                    if (setPath) {
                        page.setMenuPath(this.pathContainer.getPathById(page.getId(), false));
                    }
                }
                pageContainer.addAll(pages);
            }
//            }
        }
    }

    public ExecuteResult reqSubmit(String reqId, String version, String reqName) {
        ExecuteResult executeResult = new ExecuteResult();
        List<FeatureReq> featureReqs = this.featureReqRepository.findsByReqId(reqId);
        if (CollectionUtils.isEmpty(featureReqs)) {
            return executeResult;
        }
        if (StringUtils.isEmpty(reqName)) {
            try {
                reqName = this.getReqName(reqId);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                executeResult.setToError();
                executeResult.setMsg(e.getMessage());
                return executeResult;
            }
        }
        try {
            for (FeatureReq featureReq : featureReqs) {
                executeResult = this.submit(reqId, featureReq.getId().getFeatureId(), reqName, version);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            executeResult.setToError();
            executeResult.setMsg(e.getMessage());
        }
        return executeResult;
    }

    public Map<String, Object> getAllFeatureVersions(String featureId) throws Exception {
        Map<String, Object> rs = new HashMap<>();
        List<FeatureController.FeatureVersionVo> masterVersions = new ArrayList<>();
        List<FeatureController.FeatureVersionVo> reqVersions = new ArrayList<>();
        rs.put("master", masterVersions);
        rs.put("req", reqVersions);
        Feature dbFeature = this.featureRepository.findOne(featureId);
        if (null == dbFeature) {
            return rs;
        }
        List<FeatureHistory> featureHistories = this.featureHistoryRepository.findByFeatureId(featureId);
        if (!CollectionUtils.isEmpty(featureHistories)) {
            for (FeatureHistory featureHistory : featureHistories) {
                FeatureController.FeatureVersionVo featureVersionVo = new FeatureController.FeatureVersionVo();
                masterVersions.add(featureVersionVo);
                featureVersionVo.setFeatureId(featureId);
                featureVersionVo.setReqId("-1");
                featureVersionVo.setReqName("master");
                featureVersionVo.setVersion(featureHistory.getVersion());
                Config config = this.configService.getConfigMap(featureHistory.getAttrConfigId(), true);
                Map<String, Object> attrs = this.getObjectAttrs(config.getKVMap());
                featureVersionVo.setAttrs(attrs);
            }
        }
        FeatureController.FeatureVersionVo masterOnlineFeatureVersionVo = new FeatureController.FeatureVersionVo();
        masterOnlineFeatureVersionVo.setFeatureId(dbFeature.getId());
        masterOnlineFeatureVersionVo.setVersion("online");
        masterOnlineFeatureVersionVo.setReqId("-1");
        masterOnlineFeatureVersionVo.setReqName("master");
        Config masterConfig = this.configService.getConfigMap(dbFeature.getAttrConfigId(), true);
        masterOnlineFeatureVersionVo.setAttrs(this.getObjectAttrs(masterConfig.getKVMap()));
        masterVersions.add(masterOnlineFeatureVersionVo);


        List<VersionHistory> versionHistories = this.versionHistoryRepository.findByRelationIdAndType(featureId, "REQ_FEATURE");
        if (!CollectionUtils.isEmpty(versionHistories)) {
            for (VersionHistory versionHistory : versionHistories) {
                FeatureController.FeatureVersionVo featureVersionVo = new FeatureController.FeatureVersionVo();
                reqVersions.add(featureVersionVo);
                featureVersionVo.setFeatureId(featureId);
                featureVersionVo.setReqId(versionHistory.getReqId());
                featureVersionVo.setReqName(versionHistory.getReqName());
                featureVersionVo.setVersion(versionHistory.getVersion());
                Config reqVersionConfig = this.configService.getConfigMap(versionHistory.getAttrConfigId(), true);
                featureVersionVo.setAttrs(this.getObjectAttrs(reqVersionConfig.getKVMap()));
            }
        }


        //到这里查询所有未上线的req的submit history
        Indexing featureReqIndexing = this.indexingService.getIndexing(new IndexingId("feature_req_indexing", featureId));
        if (featureReqIndexing != null && (!CollectionUtils.isEmpty(featureReqIndexing.getIndexMap()))) {
            Map<String, String> indexMap = featureReqIndexing.getIndexMap();
            for (String reqId : indexMap.keySet()) {
                if (StringUtils.isEmpty(reqId)) {
                    continue;
                }
                FeatureController.FeatureVersionVo featureVersionVo = new FeatureController.FeatureVersionVo();
                reqVersions.add(featureVersionVo);
                featureVersionVo.setFeatureId(featureId);
                featureVersionVo.setReqId(reqId);
                featureVersionVo.setReqName(this.getReqName(reqId));
                featureVersionVo.setVersion("temp");
                FeatureReqId featureReqId = new FeatureReqId(featureId, reqId);
                FeatureReq featureReq = this.featureReqRepository.findOne(featureReqId);
                Config reqVersionConfig = this.configService.getConfigMap(featureReq.getAttrConfigId(), true);
                featureVersionVo.setAttrs(this.getObjectAttrs(reqVersionConfig.getKVMap()));
            }
        }


        return rs;
    }

    private Map<String, Object> getObjectAttrs(Map<String, String> strAttrs) {
        Map<String, Object> attrs = new HashMap<>();

        if (CollectionUtils.isEmpty(strAttrs)) {
            return attrs;
        }
        for (Map.Entry<String, String> entry : strAttrs.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (StringUtils.isEmpty(value)) {
                attrs.put(key, value);
            }
            try {
                attrs.put(key, JSON.parse(value));
            } catch (Exception e) {
                attrs.put(key, value);
            }
        }
        return attrs;
    }

}
